﻿#pragma once
#include "LuaObject.h"
#include <vector>

class LuaFunction;

class LUAOBJ_API LuaThread:public LuaObject
{
public:
    LuaThread();
    LuaThread(LuaObjectImpl* impl);
    LuaThread(LuaState* owner);

	~LuaThread();

	bool isValid();

    LuaState* thread();


#if LUA_VERSION_NUM >= 504

	template <class... T>
	std::vector<LuaObject> resume(LuaFunction func, T... args) {
		std::vector<LuaObject> rslt;
		LuaState* curThread = thread();
		if (!curThread || !func.isValid())
			return rslt;

		lua_State* L = getLuaState();

		StackOps::Push(L, func);
		StackOps::PushMulti(L, args...);

		lua_State* Lt = curThread->getLuaState();

		lua_xmove(L, Lt, sizeof...(args)+1);
		int rtn = 0;
		int code = lua_resume(Lt, L, sizeof...(args), &rtn);


		if (code != LUA_OK && code != LUA_YIELD) {
			std::string err = lua_tostring(Lt, -1);
			lua_pop(Lt, 1);
			LUA_THROW_EXCEPTION(err.c_str());
		}


		if (rtn > 0) {
			rslt.resize(rtn);
			lua_xmove(Lt, L, rtn);

			int top = lua_gettop(L);
			for (int i = 0; i < rtn; ++i) {
				rslt[i] = LuaObject(getCppLuaState(), top - rtn + i + 1);
			}
		}
		return rslt;
	}

#else

	template <class... T>
	void resume(LuaFunction func, T... args) {
		LuaState* curThread = thread();
		if (!curThread || !func.isValid())
			return;

		lua_State* L = getLuaState();

		StackOps::Push(L, func);
		StackOps::PushMulti(L, args...);

		lua_State* Lt = curThread->getLuaState();

		lua_xmove(L, Lt, sizeof...(args)+1);

		if (lua_resume(Lt, 0) < 0) {
			std::string err = lua_tostring(Lt, -1);
			lua_pop(Lt, 1);
			LUA_THROW_EXCEPTION(err.c_str());
		}
}

#endif

};
